package com.vmj.classfile.entity.attribute;

import com.vmj.classfile.ClassReader;
import com.vmj.classfile.entity.ConstantPool;

import java.util.List;

/**
 * Created by yangshoujun on 2017/8/6 下午3:33.
 */
public class CodeAttribute extends AbstractAttribute {

    private int maxStack; // u2
    private int maxLocals;// u2
    private byte[] code;  // u1[]
    private ExceptionTableEntry[] exceptionTable;
    Attribute[] attributes;

    private ConstantPool constantPool;

    public CodeAttribute(ClassReader classReader) {
        super(classReader);
    }

    public void parse() {
        ClassReader reader = getClassReader();
        this.maxStack = reader.readTwoByte();
        this.maxLocals = reader.readTwoByte();
        int codeLength = reader.readInt();
        this.code = reader.readByte(codeLength);
        readExceptionTable(reader);
        readAttributes(getClassReader());

    }

    private void readExceptionTable(ClassReader reader) {
        int exceptionTableLength = reader.readTwoByte();
        exceptionTable = new ExceptionTableEntry[exceptionTableLength];
        for(int i = 0;i < exceptionTableLength;i++) {
            ExceptionTableEntry entry = new ExceptionTableEntry();
            entry.setStartPc(reader.readTwoByte());
            entry.setEndPc(reader.readTwoByte());
            entry.setHandlerPc(reader.readTwoByte());
            entry.setCatchType(reader.readTwoByte());
            exceptionTable[i] = entry;
        }
    }

    private void readAttributes(ClassReader reader) {
        List<Attribute> list = getClassReader().readAttributes(getConstantPool());
        attributes = new Attribute[list.size()];
        for(int i = 0;i < list.size();i++) {
            attributes[i] = list.get(i);
        }
    }

    public LineNumberTableAttribute getLineNumberTableAttribute() {
        for(Attribute attr : attributes) {
            if(attr instanceof LineNumberTableAttribute) {
                return (LineNumberTableAttribute) attr;
            }
        }

        return null;
    }

    public ConstantPool getConstantPool() {
        return constantPool;
    }

    public int getMaxStack() {
        return maxStack;
    }

    public int getMaxLocals() {
        return maxLocals;
    }

    public byte[] getCode() {
        return code;
    }

    public ExceptionTableEntry[] getExceptionTable() {
        return exceptionTable;
    }

    public Attribute[] getAttributes() {
        return attributes;
    }

    public void setMaxStack(int maxStack) {
        this.maxStack = maxStack;
    }

    public void setMaxLocals(int maxLocals) {
        this.maxLocals = maxLocals;
    }

    public void setCode(byte[] code) {
        this.code = code;
    }

    public void setExceptionTable(ExceptionTableEntry[] exceptionTable) {
        this.exceptionTable = exceptionTable;
    }

    public void setAttributes(Attribute[] attributes) {
        this.attributes = attributes;
    }

    @Override
    public void setConstantPool(ConstantPool constantPool) {
        this.constantPool = constantPool;
    }
}
